# 单纯的重复不是迭代
# i = 0
# while True:
#     print(i)

# 迭代是一个重复的过程，每一次重复都是基于上一次的结果而来
# l = ['a','b',"c"]
# i = 0
# while i < len(l):
#     print(i)
#     print(l[i])
#     i += 1

# 有哪些数据类型支持这样的迭代取值
# 数据类型不可变：字符串，元组、整数、浮点型
# 数据类型可变的： 列表、集合、字典
# str1 = "asd"
# for i in str1:
#     print(i)
#
# tuple1 = (1,2,3)
# for i in tuple1:
#     print(i)

# list1 = [1,2,3,4]
# for i in list1:
#     print(i)

# dict1 = {"name":"yang","age":18}
# for i in dict1.values():
#     print(i)

# set1 = {1,2,3}
# for i in set1:
#     print(i)

# 可迭代对象

a = 1 # int
# a.__iter__()
# b.__iter__
c = "hello"
c.__iter__() # 字符串支持迭代
d = [1,3]
d.__iter__() # 集合支持
e = (1,2)
e.__iter__() # 元组支持
f = {1,2.3}
f.__iter__() # 集合支持
g = {"name":"yang"}
g.__iter__() # 字典支持
"""
通过上面的检查方式：
可迭代对象有
【字符串】、【列表】、【元组】、【集合】、【字典】
不可迭代对象有：
【整数】、【浮点型】
"""

# 迭代器
dic = {"x":1,"y":2,"z":3}
iter_dic = dic.__iter__() # 创建迭代器对象
# print(iter_dic) # 返回一个地址值 <method-wrapper '__iter__' of dict object at 0x0000027673712940>
# todo：通过__next__方法，取它的下一个值
# print(iter_dic.__next__()) # x
# print(iter_dic.__next__()) # y
# print(iter_dic.__next__()) # z
# print(iter_dic.__next__()) # 报错 StopIteration 表示所有的迭代器对象都取空了

# print(dic[eval("iter_dic.__next__()")])
# print(dic[eval("iter_dic.__next__()")])
# print(dic[eval("iter_dic.__next__()")])
# print(dic[eval("iter_dic.__next__()")]) # 报错 StopIteration 表示所有的迭代器对象都取空了
# # print(iter_dic.__next__())

# 迭代器误区
"""dic1 = {"x":1,"y":2,"z":3}
# 这样的话，就相当于每一次都创建了新的迭代器对象
print(dic1.__iter__().__next__()) # x
print(dic1.__iter__().__next__()) # x
print(dic1.__iter__().__next__()) # x
print(dic1.__iter__().__next__()) # x"""


# 迭代器为什么和for循环一起用

# 先看while循环
l1 = [1,2,3]
iter_l1 = l1.__iter__()
# while True:
#     print(next(iter_l1)) # 这个等于 iter_l1.__next__()

# while True:
#     try:
#         print(next(iter_l1)) # 尝试性去打印
#     except StopIteration as e:
#         print(f"报错提示:{e}")
#         break # 取空了就没有必要循环了
#     finally:
#         print("本次输出结束！")

# for i in l1:
#     print(i) # 直接就可以不断地拿下一个值

"""
直接进行for循环，为我们做了很多事情：
1、直接根据这个数据类型创建了迭代器
2、不断地循环访问下一个
3、直到都拿完了之后，会去捕捉异常处理，不会展示错误
"""

# 还记得range吗
obj_iter = range(1,10)
# print(obj_iter) # 直接返回的就是原始打印的内容  todo:range(1, 10)
# print(list(obj_iter)) # 可以转成列表对象去使用  [1, 2, 3, 4, 5, 6, 7, 8, 9]
# print(tuple(obj_iter))  # 可以转成元租对象去使用 (1, 2, 3, 4, 5, 6, 7, 8, 9)

# todo:创建迭代器对象
# obj = obj_iter.__iter__()
# # 结合__next__()方法不断访问下一个
# print(obj.__next__())
# print(obj.__next__())
# print(obj.__next__())
# print(obj.__next__())
# print(obj.__next__())
# print(obj.__next__())
# print(obj.__next__())

# 问题
# print("迭代器的for循环下了三个鸡蛋的母鸡")
# for i in obj:
#     # 从1开始还是从8开始
#     print(i) # 接着从8开始，因为前面有7个鸡蛋被拿走了
# print("再次")
# for i in obj:
#     print(i) # 打印为空，迭代器对象没有值可以取了
# print("可迭代对象的for循环没下蛋的母鸡")
# for i in obj_iter:
#     print(i) # 有值，相当于一个新的可迭代对象
# print("再次")
# for i in obj_iter:
#     print(i) # 依然有值，一个新的可迭代对象


# 生成器 yield
# def gg():
#     a = 1 # 创建了一个a变量，初始值为1
#     while True:
#         yield a # todo：生成器，也可以把它理解为 return 值
#         a += 1 # 每一次a都会+=1
#
# a1 = gg()
# # print(a1)  # 返回一个对象 <generator object gg at 0x000001CE2D3F9430>
# print(next(a1)) # 1
# print(next(a1)) # 2
# print(next(a1)) # 3
















# 生成器
# def g():
#     a = 1
#     while True:
#         yield a # return 第一次的时候，返回1  第二次的时候，返回 2  第三次返回3
#         a += 1 # a+=1 a+=1
# #todo：next函数可用于引起生成器/迭代器的下一次生成/迭代。其返回值就是下一个生成的值。
#
# # 通过 next(generator) 这一方式，可以获得一系列值。
# print("这是一个测试语句！")
# a1 = g()
# print(a1) # 返回的是一个对象 <generator object g at 0x0000023503A39430>
# print(next(a1)) # 1
# print(next(a1)) # 2
# print(next(a1)) # 3

